/**
 * Mixins 类型辅助工具
 * @see https://github.com/ktsn/vue-typed-mixins/blob/master/src/index.ts
 */

import Vue, { type ComponentOptions, type VueConstructor } from 'vue'

type VueMixin = VueConstructor | ComponentOptions<never>

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
  k: infer I
) => void
  ? I
  : never

type ExtractInstance<T> =
  T extends VueConstructor<infer V>
    ? V
    : T extends ComponentOptions<infer V>
      ? V
      : never

type MixedVueConstructor<Mixins extends VueMixin[]> = Mixins extends (infer T)[]
  ? VueConstructor<UnionToIntersection<ExtractInstance<T>> & Vue>
  : never

export function Mixins<Mixins extends VueMixin[]>(
  ...mixins: Mixins
): MixedVueConstructor<Mixins>
export function Mixins(
  ...mixins: (VueConstructor | ComponentOptions<Vue>)[]
): VueConstructor {
  return Vue.extend({ mixins })
}
